/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package elsimulatorjava;

import java.util.ArrayList;
import java.util.List;

/**
 *
 * @author jc238592
 */
public class Elevator {

    public enum ElevatorState{
        MOVING,
        DOOR_OPENING,
        DOOR_OPEN,
        DOOR_CLOSING,
        IDLE, 
        Closed
    }

    public enum ElevatorDirection{
        UP,
        DOWN,
        NONE
    }

    private static short elevatorCount = 0;
    private short index;

    private ElevatorState state = ElevatorState.IDLE;
    private int doorOpen;

    //
    private short lastFloor;

    // People in the elevator
    private ArrayList<Person> people;
    private byte maximumCapacity;

    private short maxFloor;
    private short minFloor;
    private short position;
    private int posDecimal;
    private int numberOfIterationsItTakesForElevatorToReachNextFloor;
    private ElevatorDirection direction;

    private static double speed = 1;

    private boolean[] floorList;
    private boolean emergencyStop;

    /*
     * Elevator constructor
     */
    Elevator(short minF, short maxF, short fPos, byte maxCapacity, boolean[] bl) {
        this.minFloor = minF;
        this.maxFloor = maxF;
        this.floorList = bl;
        doorOpen = 0;
        this.position = fPos;
        lastFloor = fPos;
        this.maximumCapacity = maxCapacity;
        direction = ElevatorDirection.NONE;

        people = new ArrayList<Person>();
        this.index = elevatorCount++;

        this.emergencyStop = false;
        
        numberOfIterationsItTakesForElevatorToReachNextFloor = 50;
    }

        // Functions
    protected boolean noPeopleInside() {
        return people.isEmpty();
    }

    protected void changeDoorSize(byte deltaSize) {
        if (deltaSize > 0){
            doorOpen += deltaSize;
            if (doorOpen >= 10) {
                doorOpen = 10;
                state = ElevatorState.DOOR_OPEN;
            }
        } else {
            doorOpen += deltaSize;
            if (doorOpen <= 0) {
                if (!noPeopleInside() || this.position != this.lastFloor) {
                    setFurthestAwayFloorToGoTo();
                    state = ElevatorState.MOVING;
                }
                else {
                    state = ElevatorState.IDLE;
                }
                doorOpen = 0;

            }
        }
    }

    private void setFurthestAwayFloorToGoTo() {
        short furthestAwayFloor = (short) position;
        if (this.direction == ElevatorDirection.DOWN) {
            for (Person person :  people) {
                if (person.getFloorDest() < furthestAwayFloor) {
                    furthestAwayFloor = (short) person.getFloorDest();
                }
            }
        }
        else if (this.direction == ElevatorDirection.UP) {
            for (Person person :  people) {
                if (person.getFloorDest() > furthestAwayFloor) {
                    furthestAwayFloor = (short) person.getFloorDest();
                }
            }
        } 
        lastFloor = furthestAwayFloor;
    }

    public void moveElevator(short speed) {
        position += speed;
    }

    public void addPerson(Person p) {
        people.add(p);
    }

    protected void removePerson(Person p){
        people.remove(p);
    }

    // Updates position for elevator
    void changePosition() {
            switch (this.direction){
                case UP:
                    this.posDecimal += this.speed;
                    if (this.posDecimal % numberOfIterationsItTakesForElevatorToReachNextFloor == 0){
                        this.posDecimal = 0;
                        if (this.position < this.lastFloor){
                                this.position += 1;
                            } else if (this.position > this.lastFloor) {
                                this.position -=1;
                            }
                        if ((this.isDestFloor() || this.position == this.lastFloor)){
                                this.state = ElevatorState.DOOR_OPENING;
                            }
                    }
                    break;
                case DOWN:
                    this.posDecimal += this.speed;
                    if (this.posDecimal % numberOfIterationsItTakesForElevatorToReachNextFloor == 0){
                        this.posDecimal = 0;
                        if (this.position < this.lastFloor){
                                this.position += 1;
                            } else if (this.position > this.lastFloor) {
                                this.position -=1;
                            }
                        if ((this.isDestFloor() || this.position == this.lastFloor)){
                                this.state = ElevatorState.DOOR_OPENING;
                            }
                    }
                    break;
            }
    }

    /*
     * If a person wants to stop here, it will return true,
     * otherwise it will return false.
     */
    boolean isDestFloor() {
        for (Person person : people) {
            if (person.getFloorDest() == position) {
                return true;
            }
        }
        return false;
    }
    
    boolean isDestFloor(short fN) {
        for (Person person : people) {
            if (person.getFloorDest() == fN) {
                return true;
            }
        }
        return false;
    }

    public boolean isNotFull() {
        if (maximumCapacity > this.people.size()){
            return true;
        } else {
            return false;
        }
    }

    // Getters and setters
    protected int getElevatorIdx() {
        return this.index;
    }

    protected void setState(ElevatorState state) {
            this.state = state;
    }

    protected ElevatorState getState() {
            return state;
    }

    protected void setDoor(byte doorOpen) {
            this.doorOpen = doorOpen;
    }

    protected double getDoor() {
        double doorDouble = doorOpen/(double)10;
            return doorDouble;
    }

    protected void setDirection(ElevatorDirection d) {
        this.direction = d;
    }

    protected ElevatorDirection getDirection() {
        return direction;
    }

    protected void setPosition(short position) {
        this.position = position;
    }

    protected short getPosition() {
        return position;
    }
    
    public double getProperPosition() {
        double properPosition = position;
        if (this.position < this.lastFloor){
                    properPosition += (double)posDecimal/ (double)numberOfIterationsItTakesForElevatorToReachNextFloor;
                } else if (this.position > this.lastFloor){
                    properPosition -= (double)posDecimal/ (double)numberOfIterationsItTakesForElevatorToReachNextFloor;
                }
                
        /*switch (direction) {
            case UP:
                if (this.position < this.lastFloor){
                    properPosition += (double)posDecimal/ (double)numberOfIterationsItTakesForElevatorToReachNextFloor;
                } else if (this.position > this.lastFloor){
                    properPosition -= (double)posDecimal/ (double)numberOfIterationsItTakesForElevatorToReachNextFloor;
                }
                break;
                
            case DOWN:
                if (this.position < this.lastFloor){
                    properPosition += (double)posDecimal/ (double)numberOfIterationsItTakesForElevatorToReachNextFloor;
                } else if (this.position > this.lastFloor){
                    properPosition -= (double)posDecimal/ (double)numberOfIterationsItTakesForElevatorToReachNextFloor;
                }
        }*/
        return properPosition;
    }

    protected List<Person> getPeople() {
        return people;
    }


    protected void setMaxNumberOfPeople(byte maxNumber) {
        maximumCapacity =  maxNumber;
    }

    protected byte getMaxNumberOfPeople() {
        return maximumCapacity;
    }

    protected byte getPeopleCount() {
        return (byte) this.people.size();
    }

    protected boolean goesToFloor(int floorID) {
        return floorList[floorID];
    }

    protected void setLastFloor(short f){
        this.lastFloor = f;
    }
    
    protected short getLastFloor(){
        return this.lastFloor;
    }
    
  /*  void setEmergencyStop(boolean stop){
        if (stop){
            this.emergencyStop = true;
        } else {
            this.emergencyStop = false;
            this.timer = new Date();
        }
    }*/
    protected short getIndex(){
        return this.index;
    }
    
    protected boolean isDoorClosed(){
        boolean doorClosed = false;
        if (this.doorOpen == 0){
            doorClosed = true;
        } else {
            doorClosed = false;
        }
        
        return doorClosed;
    }

    
    static void resetCounter(){
        elevatorCount = 0;
    }
    
    public int getMaxFloor() {
        return maxFloor;
    }
    
    public boolean[] getAllowedFloorList() {
        return floorList;
    }
    
    public int getPosDecimal() {
        return posDecimal;
    }
    
    public void setPosDecimal(int posDecimal) {
        this.posDecimal = posDecimal;
    }
    
    public int getDoorOpen() {
        return doorOpen;
    }
    
    public void setDoorOpen(int doorOpen) {
        this.doorOpen = doorOpen;
    }
}